<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Nested Effects</title>
    </head>
    <body>
        <h1>Nested Effects</h1>
        <script>
            let activeEffect;
            const effectStack = [];
            function effect(fn) {
                const effectFn = () => {
                    cleanup(effectFn);
                    activeEffect = effectFn;
                    effectStack.push(effectFn);
                    fn();
                    effectStack.pop();
                    activeEffect = effectStack[effectStack.length - 1];
                };

                effectFn.deps = [];
                effectFn();
            }

            function cleanup(effectFn) {
                for (let i = 0; i < effectFn.deps.length; i++) {
                    const deps = effectFn.deps[i];
                    deps.delete(effectFn);
                }
                effectFn.deps.length = 0;
            }

            const data = {
                foo: true,
                bar: true,
            };

            let temp1, temp2;

            const bucket = new WeakMap();
            const obj = new Proxy(data, {
                get(target, key) {
                    track(target, key);
                    return target[key];
                },

                set(target, key, value) {
                    target[key] = value;
                    trigger(target, key);
                    return true;
                },
            });

            function track(target, key) {
                if (!activeEffect) return;

                let depsMap = bucket.get(target);
                if (!depsMap) {
                    bucket.set(target, (depsMap = new Map()));
                }

                let deps = depsMap.get(key);
                if (!deps) {
                    depsMap.set(key, (deps = new Set()));
                }

                deps.add(activeEffect);

                activeEffect.deps.push(deps);
            }

            function trigger(target, key) {
                const depsMap = bucket.get(target);
                if (!depsMap) return;

                const effects = depsMap.get(key);

                const effectsToRun = new Set(effects);
                effectsToRun.forEach((effectFn) => effectFn());
            }

            effect(function effectFn1() {
                console.log('effectFn1 执行');

                effect(function effectFn2() {
                    console.log('effectFn2 执行');
                    temp2 = obj.bar;
                });

                temp1 = obj.foo;
            });
        </script>
    </body>
</html>
